package my.http;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 当channelRead0()方法完成时，你已经有了传入消息，并且已经处理完它了。当该方法返回时，
 * SimpleChannelInboundHandler负责释放指向保存该消息的ByteBuf的内存引用。
 * 当writeAndFlush()方法被调用时ByteBuf也会被释放。
 * @author fengbo
 * @date 2018/10/2
 */
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private static final Logger log = LoggerFactory.getLogger(HttpServerHandler.class);

    private static final String ROOT_PATH = HttpServerHandler.class.getResource("/").getPath()
         + "static";

    private static final Map<String, String> CONTEXT_TYPE = new HashMap<>(16);

    static {
        CONTEXT_TYPE.put("html", "text/html; charset=UTF-8");
        CONTEXT_TYPE.put("css", "text/css; charset=UTF-8");
        CONTEXT_TYPE.put("js", "application/x-javascript");
        CONTEXT_TYPE.put("svg", "image/svg+xml");
        CONTEXT_TYPE.put("png", "image/png");
        CONTEXT_TYPE.put("jpg", "application/x-jpg");
        CONTEXT_TYPE.put("ico", "application/x-jpg");
        CONTEXT_TYPE.put("mp4", "video/mpeg4");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws IOException {

        if (!request.decoderResult().isSuccess()) {
            sendError(ctx, HttpResponseStatus.BAD_REQUEST);
            return;
        }

System.out.println(Thread.currentThread().getName() + "=======================header start=======================");
        List<Map.Entry<String, String>> headers = request.headers().entries();
        for (Map.Entry<String, String> header : headers) {
System.out.println(header.getKey() + ":" + header.getValue());
        }
System.out.println(Thread.currentThread().getName() + "=======================header end=======================");

System.out.println(Thread.currentThread().getName() + "=======================body start=======================");
        ByteBuf requestBody = request.content();
        CharSequence body = requestBody.readCharSequence(requestBody.readableBytes(), CharsetUtil.UTF_8);
System.out.println(body);
System.out.println(Thread.currentThread().getName() + "=======================body end=======================");

        if (!HttpMethod.GET.equals(request.method())) {
            sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
            return;
        }

        // 根据URL获取对应的文件
        String uri;
        try {
            uri = ROOT_PATH + URLDecoder.decode(request.uri().trim(), CharsetUtil.UTF_8.name());
            log.info("request uri is {}.", uri);
        } catch (UnsupportedEncodingException e) {
            throw new IllegalArgumentException("parse url error!!!", e);
        }
        String endExt = "/";
        if (uri.endsWith(endExt)) {
            uri += "index.html";
        }

        // 设置Response Header和Body
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
        boolean keepAlive = HttpUtil.isKeepAlive(request);
        if (keepAlive) {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
        File file = new File(uri);
        try (FileInputStream fis = new FileInputStream(file)) {
//            ctx.write(new DefaultFileRegion(fis.getChannel(), 0, file.length()));
            response.content().writeBytes(fis.getChannel(), 0L, Long.valueOf(file.length()).intValue());
        }
        HttpUtil.setContentLength(response, response.content().readableBytes());
        // 设置CONTENT_TYPE
        int dotPos = uri.lastIndexOf(".");
        String fileExt = uri.substring(dotPos + 1);
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, CONTEXT_TYPE.get(fileExt));

        if (!keepAlive) {
            ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
        } else {
            response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
            ctx.writeAndFlush(response);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        log.error(cause.getMessage(), cause);
        if (ctx.channel().isActive()) {
            sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
                Unpooled.copiedBuffer("Failure: " + status, CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}
